home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_pcdp
/
adas
/
util.pas
< prev
Wrap
Pascal/Delphi Source File
|
1996-01-30
|
12KB
|
473 lines
unit util;
{ Utility programs: lexical analyzer and
compiler table manipulation }
interface
uses global;
procedure nextch;
procedure error(n: er);
procedure fatal(n: integer);
procedure insymbol;
procedure enterst(x0: alfa; x1: object; x2: types; x3:integer);
function loc(level: integer; id: alfa): integer;
procedure enter(id: alfa; k: object; level: integer);
procedure enterarray(tp: types; l,h: integer);
procedure enterblock;
procedure emit(fct: integer);
procedure emit1(fct, b: integer);
procedure emit2(fct, a, b: integer);
procedure printinst(var f: text; i: integer);
procedure initutil;
var
{ The following variables are used by the various
units comprising the compiler }
inp: text; { input file }
list: text; { list file }
listing: boolean; { listing flag }
sy: symbol; { current symbol }
id: alfa; { name of current identifier }
inum: integer; { value of integer constant }
sleng: integer; { length of string constant }
a: integer; { array counter }
b: integer; { block counter }
t: integer; { symbol table index }
lc: integer; { location counter in code table }
const
{ keywords must be in alphabetical order for binary search }
key: array[1..nkw] of alfa = (
'accept ' , 'and ' , 'array ' , 'begin ' ,
'body ' , 'constant ' , 'do ' , 'else ' ,
'elsif ' , 'end ' , 'exit ' , 'for ' ,
'if ' , 'in ' , 'is ' , 'loop ' ,
'mod ' , 'not ' , 'null ' , 'of ' ,
'or ' , 'out ' , 'pragma ' , 'procedure ' ,
'select ' , 'task ' , 'terminate ' , 'then ' ,
'type ' , 'when ' , 'while '
);
{ this table of symbols must match the above table of keywords }
ksy: array[1..nkw] of symbol = (
acceptsy, andsy, arraysy, beginsy,
bodysy, constsy, dosy, elsesy,
elsif, endsy, exitsy, forsy,
ifsy, insy, issy, loopsy,
imod, notsy, nullsy, ofsy,
orsy, outsy, pragmasy, proceduresy,
selectsy, tasksy, terminate, thensy,
typesy, when, whilesy
);
const
constbegsys : symset = [plus, minus, intcon, charcon, ident];
typebegsys : symset = [ident, arraysy];
blockbegsys : symset = [constsy, typesy, proceduresy,
beginsy, tasksy];
facbegsys : symset = [intcon, charcon, ident, lparent, notsy];
statbegsys : symset = [ident, beginsy, ifsy, whilesy, loopsy,
acceptsy, exitsy, forsy, selectsy, nullsy];
implementation
var
line: array[1..llng] of char;
cc: integer; { character counter within input line }
ll: integer; { length of line as read from input }
savell: integer; { saved ll for error message }
sx: integer; { current end of string table }
ch: char; { last character read }
const
fatalmsg: array[1..7] of alfa = (
'identifer ', 'procedures', 'strings ', 'arrays ',
'levels ', 'code ', 'entries ' );
procedure initutil;
begin
lc := 0;
cc := 0;
ll := 0;
sx := 0;
ch := ' '
end;
procedure nextch;
{ returns next character in ch, checking for eol and eof }
begin
if cc=ll then
begin
if eof(inp) then
begin
writeln;
writeln('program incomplete');
if listing then close(list);
halt
end;
if listing then write(list, lc:5, ' ');
savell := ll;
ll := 0;
cc := 0;
while not eoln(inp) do
begin
ll := ll + 1;
read(inp, ch);
if ch < ' ' then ch := ' ';
if listing then write(list, ch);
line[ll] := ch
end;
if listing then writeln(list);
ll := ll + 1;
read(inp, line[ll]);
if line[ll] < ' ' then line[ll] := ' ';
end;
cc := cc + 1;
ch := line[cc]
end;
procedure error(n: er);
{ print error code and halt }
var i: integer;
begin
if listing then
begin
write(list, '*****', ' ':cc, '^', ord(n):2);
close(list)
end;
writeln('Compilation error:');
for i := 1 to ll do write(line[i]);
writeln;
writeln(' ':cc-1, '^', ord(n):2);
readln;
halt
end;
procedure fatal(n: integer);
{ print fatal error and halt }
begin
writeln;
writeln('compiler table for ', fatalmsg[n], ' is too small');
readln;
halt
end;
procedure insymbol;
{ lexical analyzer: get next symbol and return in sy
also set id, inum, sleng, as needed }
label 1,2,3;
var i,j,k,e: integer;
quotech: char;
begin
1:while ch = ' ' do nextch;
case ch of
'a'..'z', 'A'..'Z':
begin
k := 0;
id := ' ';
repeat
if k < alng then { use only alng chars of identifier }
begin
k := k + 1;
if ch in ['A'..'Z']
then
id[k] := chr(ord(ch)+ord('a')-ord('A'))
else id[k] := ch
end;
nextch
until not (ch in ['a'..'z', 'A'..'Z', '0'..'9', '_']);
i := 1;
j := nkw;
repeat { binary search for keywords }
k := (i+j) div 2;
if id <= key[k] then j := k-1;
if id >= key[k] then i := k+1;
until i > j;
if i-1 > j then sy := ksy[k] else sy := ident
end;
'0'..'9': { convert numerals to numbers }
begin
k := 0;
inum := 0;
sy := intcon;
repeat
inum := inum*10 + ord(ch) - ord('0');
k := k + 1;
nextch
until not (ch in ['0'..'9']);
if k>kmax then
begin
error(erln);
inum := 0;
k := 0
end;
end;
':':
begin
nextch;
if ch = '=' then begin sy := becomes; nextch end
else sy := colon
end;
'<':
begin
nextch;
if ch = '=' then begin sy := leq; nextch end
else sy := lss
end;
'/':
begin
nextch;
if ch = '=' then begin sy := neq; nextch end
else sy := idiv
end;
'>':
begin
nextch;
if ch = '=' then begin sy := geq; nextch end
else sy := gtr
end;
'"', '''': { characters and strings }
begin
quotech := ch;
k := 0;
2: nextch;
if ch = quotech then
begin
nextch;
if ch <> quotech then goto 3
end;
if sx + k = smax then fatal(3);
stab[sx+k] := ch;
k := k + 1;
if cc = 1 then k := 0
else goto 2;
3: if (k = 1) and (quotech = '''') then
begin
sy := charcon;
inum := ord(stab[sx]);
end
else if (k = 0) or (quotech = '''') then
begin
error(ersh);
sy := charcon;
inum := 0
end
else begin
sy := strng;
inum := sx;
sleng := k;
sx := sx + k
end
end;
'-': { -- starts a comment, ignore rest of line }
begin
nextch;
if ch <> '-' then sy := minus else
begin cc := ll; nextch; goto 1 end
end;
'=':
begin
nextch;
if ch = '>' then begin sy := arrow; nextch end
else sy := eql
end;
'.':
begin
nextch;
if ch = '.' then begin sy := colon; nextch end
else sy := period
end;
'+': begin sy := plus; nextch end;
'(': begin sy := lparent; nextch end;
'*': begin sy := times; nextch end;
')': begin sy := rparent; nextch end;
',': begin sy := comma; nextch end;
';': begin sy := semicolon; nextch end;
else
begin
error(erch);
nextch;
goto 1
end
end (* case *);
end;
procedure enterst(x0: alfa; x1: object; x2: types; x3: integer);
{ enter a pre-defined symbol into the symbol table }
begin
t := t + 1;
with tab[t] do
begin
name := x0;
link := t - 1;
obj := x1;
typ := x2;
ref := 0;
normal := true;
lev := 0;
adr := x3
end
end;
procedure enterarray(tp: types; l,h: integer);
{ enter an array into the array table }
begin
if l > h then error(ertyp);
if a = amax then fatal(4);
a := a + 1;
with atab[a] do
begin
inxtyp := tp;
low := l;
high := h
end
end;
procedure enterblock;
{ enter a block into the block table }
begin
if b = bmax then fatal(2);
b := b + 1;
btab[b].last := 0;
btab[b].lastpar := 0
end;
procedure emit(fct: integer);
{ emit a parameterless instruction into the code table }
begin
if lc = cmax then fatal(6);
code[lc].f := fct;
if listing then
begin
write(list, lc:10, ' ');
printinst(list, fct);
writeln(list, fct:5);
end;
lc := lc + 1
end;
procedure emit1(fct, b: integer);
{ emit a one-parameter instruction }
begin
if lc = cmax then fatal(6);
with code[lc] do
begin
f := fct;
y := b
end;
if listing then
begin
write(list, lc:10,' ');
printinst(list, fct);
writeln(list, fct:5,b:5);
end;
lc := lc + 1
end;
procedure emit2(fct, a, b: integer);
{ emit a two-parameter instruction }
begin
if lc = cmax then fatal(6);
with code[lc] do
begin
f := fct;
x := a;
y := b
end;
if listing then
begin
write(list, lc:10, ' ');
printinst(list, fct);
writeln(list, fct:5,a:5,b:5);
end;
lc := lc + 1
end;
procedure enter(id: alfa; k: object; level: integer);
{ enter a symbol into the symbol table,
checking down the link fields to see if the symbol
is duplicated AT THE SAME LEVEL }
var j,l: integer;
begin
if t = tmax then fatal(1);
tab[0].name := id;
j := btab[display[level]].last;
l := j;
while tab[j].name <> id do
j := tab[j].link;
if j <> 0 then error(erdup);
t := t + 1;
with tab[t] do
begin
name := id;
link := l;
obj := k;
typ := notyp;
ref := 0;
lev := level;
adr := 0
end;
btab[display[level]].last := t
end;
function loc(level: integer; id: alfa): integer;
{ see if a name has been defined,
including at lower (more global) levels }
var i,j: integer;
begin
i := level;
tab[0].name := id;
repeat
j := btab[display[i]].last;
while tab[j].name <> id do
j := tab[j].link;
i := i - 1
until (i < 0) or (j <> 0);
loc := j
end;
procedure printinst(var f: text; i: integer);
{ print the name of a byte code instruction }
begin
case i of
0..2, 24, 34: write(f, 'load ');
3: write(f, 'display ');
4: write(f, 'cobegin ');
5: write(f, 'coend ');
6: write(f, 'wait ');
7: write(f, 'signal ');
10: write(f, 'jump ');
11: write(f, 'cond jump ');
14,15: write(f, 'for ');
18: write(f, 'mark stack');
19: write(f, 'call proc ');
21: write(f, 'index ');
31: write(f, 'end prog ');
32: write(f, 'end proc ');
38: write(f, 'store ');
35, 36, 45..59: write(f, 'ALU ');
27..29, 62,63: write(f, 'I/O ');
74: write(f, 'call entry');
75: write(f, 'accept ');
70..73, 76..79: write(f, 'entry parm');
80: write(f, 'end accept');
81: write(f, 'select ');
82: write(f, 'terminate ');
83: write(f, 'end select');
else write(f, ' ')
end
end;
end.